#include "threadPool.h"

extern conn_info client[1024];

int tcp_init(char *ip, char *port) {
  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  int flag = 1;
  setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));

  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(atoi(port));
  addr.sin_addr.s_addr = inet_addr(ip);
  bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
  listen(sockfd, 100);

  return sockfd;
}

ssize_t recvn(int fd, void *buf, ssize_t length) {
  char *p = (char *)buf;
  ssize_t total = 0;
  while (total < length) {
    ssize_t recv_ret = recv(fd, p + total, length - total, 0);
    if (recv_ret <= 0) {
      fprintf(stderr, "client disconnect. recv abort.\n");
      return recv_ret;
    }
    total += recv_ret;
  }
  return total;
}

ssize_t sendn(int fd, const void *buf, ssize_t length) {
  char *p = (char *)buf;
  ssize_t total = 0;
  while (total < length) {
    ssize_t send_ret = send(fd, p + total, length - total, MSG_NOSIGNAL);
    if (send_ret <= 0) {
      fprintf(stderr, "client disconnect. send abort.\n");
      return send_ret;
    }
    total += send_ret;
  }
  return total;
}


ssize_t send_tlv(int netfd, const void *buf, ssize_t len) {
  // 1. 发送长度字段
  ssize_t net_len = len;
  if (sendn(netfd, &net_len, sizeof(net_len)) != sizeof(net_len)) {
    return -1;
  }
  // 2. 发送数据部分
  if (sendn(netfd, buf, len) != len) {
    return -1;
  }
  // 3. 发送空的 JWT（全零）
  char empty_jwt[JWT_LEN] = {0}; // 初始化全零
  if (sendn(netfd, empty_jwt, JWT_LEN) != JWT_LEN) {
    return -1;
  }

  return len + JWT_LEN; // 返回总发送字节数
}

ssize_t recv_tlv(int netfd, TLV *tlv) {
  ssize_t len;
  ssize_t ret;

  // 接收长度字段
  ret = recvn(netfd, &len, sizeof(ssize_t));
  if (ret != sizeof(ssize_t)) {
    // 连接断开或错误（ret <= 0）
    return ret;
  }
  tlv->len = len;
  // 接收数据部分
  ret = recvn(netfd, tlv->data, tlv->len);
  if (ret != tlv->len) {
    return -1; // 数据接收不完整或断开
  }
  // 接收JWT
  ret = recvn(netfd, tlv->jwt, JWT_LEN);
  if (ret != JWT_LEN) {
    return -1; // JWT接收不完整或断开
  }
  tlv->jwt[JWT_LEN] = '\0'; // 确保字符串终止

  return tlv->len + JWT_LEN; // 返回总接收字节数
}


void send_err(int netfd, const char *msg) {
  char msg_c[2048] = {0};
  strcpy(msg_c, msg);
  send_tlv(netfd, msg_c, strlen(msg_c));
}

char *Command[] = {"cd",    "ls",    "puts",  "gets",   "pwd",
                   "mkdir", "rmdir", "login", "signup", "tree"};

char *No_Authenticate[] = {"login", "signup", "puts", "gets"};

void *(*f[])(void *, MYSQL *) = {cd_c,    ls_c,    puts_c,  gets_c,    pwd_c,
                                 mkdir_c, rmdir_c, login_c, sign_up_c, tree_c};

int need_auth(char *cmd) {
  int n = sizeof(No_Authenticate) / sizeof(No_Authenticate[0]);
  for (int i = 0; i < n; i++) {
    if (strcmp(No_Authenticate[i], cmd) == 0) {
      return 0;
    }
  }
  return 1;
}

int analyze(char *jwt, char *cmd, Task *t, int netfd, int epfd,
            threadPool *pool, conn_info *client, int *index) {
  char *div_cmd[1] = {0};
  char *div_para[1024] = {0};

  div_cmd[0] = strtok(cmd, " \n");
  if (!div_cmd[0])
    return -1;

  int k = index[netfd];
  LOG_CLIENT_EVENT(LOG_INFO, client[k], "Command received: %s", div_cmd[0]);

  printf("user name:%s\njwt:%s\n", client[k].user_name, jwt);
  // 令牌错误并且访问了需要鉴权的接口，则阻止
  if (!verify_jwt(client[k].user_name, jwt) && need_auth(div_cmd[0])) {
    fprintf(stderr, "Authenticate Failed!\n");
    send_err(netfd,"Authenticate Failed!\n");
    return -1;
  }

  // 已经登录无需再次登录
    if (strcmp(div_cmd[0], "login") == 0 &&verify_jwt(client[k].user_name, jwt)) {
    printf("user already login.\n");
    send_err(netfd, "user already login.\n");
    return -1;
  }

  int idx = 0;
  char *token;
  while ((token = strtok(NULL, " \n")) != NULL) {
    div_para[idx] = strdup(token);
    if (!div_para[idx]) {
      break;
    }
    idx++;
  }
  div_para[idx] = NULL;

  int n = sizeof(Command) / sizeof(Command[0]);
  for (int i = 0; i < n; i++) {
    if (strcmp(div_cmd[0], Command[i]) == 0) {
      t->func = f[i];
      Para *para = (Para *)malloc(sizeof(Para));
      para->netfd = netfd;
      para->epfd = epfd;

      int path_count = idx + 1;
      char **path_copy = (char **)malloc(path_count * sizeof(char *));
      if (!path_copy) {
        for (int i = 0; i < idx; ++i)
          free(div_para[i]);
        return -1;
      }
      memcpy(path_copy, div_para, path_count * sizeof(char *));
      para->path = path_copy;

      para->pool = pool;
      para->client = client;
      para->index = index;
      t->arg = para;
      return 0;
    }
  }

  for (int i = 0; i < idx; ++i) {
    free(div_para[i]);
  }

  return -1;
}

int get_real_path(char *ret_path, char *real_path, Para *para, userInfo *u) {

  char *path = para->path[0];
  deal_path(path, ret_path);

  int k = para->index[para->netfd];
  int ret_find =
      user_table_find(para->pool->user_map, para->client[k].user_name, u);
  if (ret_find != 0) {
    return -1;
  }
  strcat(real_path, u->prefix);
  strcat(real_path, ret_path);
  printf("%s\n", real_path);

  int exist = path_exist(real_path);
  if (!exist) {
    return -1;
  }
  return 0;
}


void *rmdir_c(void *arg, MYSQL *conn) {
  Para *para = (Para *)arg;
  int num = 0, offset = 0;
  DIR_S **dirs;

  char *user_name = para->path[0];
  char *path = para->path[1];
  char ret_path[2048] = {0};
  deal_path(path, ret_path);
  char uid[100] = {0};
  userInfo u;
  int ret_find = user_table_find(para->pool->user_map, user_name, &u);
  if (ret_find != 0) {
    char sql[4096] = {0};
    sprintf(sql, "select user_id from user where user_name = '%s'", user_name);
    int qret = mysql_query(conn, sql);
    if (qret != 0) {
      fprintf(stderr, "mysql_query: %s\n", mysql_error(conn));
    }

    MYSQL_RES *table = mysql_store_result(conn);
    if (mysql_num_rows(table) == 0 || mysql_num_fields(table) == 0) {
      send_err(para->netfd, "user is not exist.");
      fprintf(stderr, "user: %s is not exist.\n", user_name);
      return NULL;
    }
    MYSQL_ROW row = mysql_fetch_row(table);
    strcpy(uid, row[0]);
  } else {
    sprintf(uid, "%d", u.user_id);
  }
  dirs = (DIR_S **)queryVFS(uid, &num, conn);
  if (num > 0) {
    char *buffer = (char *)malloc(4096 * sizeof(char));
    for (int i = 0; i < num; i++) {
      if (strcmp(dirs[i]->filepath, "/") == 0) {
        collect(dirs[i], buffer, &offset);
        break;
      }
    }
    snprintf(buffer + offset, BUFFER_SIZE - offset, " ) ");
    freeDirs(dirs, num);

    char dest[1024] = "delete from vfs where file_id in ";

    strcat(dest, buffer); // 将src的内容添加到dest的末尾
    printf("%s\n", dest);
    if (mysql_query(conn, dest)) {
      printf("删除失败\n");
    }
    freeDirs(dirs, num);
    free(buffer);
  } else {
    free(dirs);
  }
  return NULL;
}

void *tree_c(void *arg, MYSQL *conn) {
  int num = 0, offset = 0;
  DIR_S **dirs;

  Para *para = (Para *)arg;
  char *user_name = para->path[0];
  char *path = para->path[1];
  char ret_path[2048] = {0};
  deal_path(path, ret_path);
  char uid[100] = {0};
  userInfo u;
  int ret_find = user_table_find(para->pool->user_map, user_name, &u);
  if (ret_find != 0) {
    char sql[4096] = {0};
    sprintf(sql, "select user_id from user where user_name = '%s'", user_name);
    int qret = mysql_query(conn, sql);
    if (qret != 0) {
      fprintf(stderr, "mysql_query: %s\n", mysql_error(conn));
    }

    MYSQL_RES *table = mysql_store_result(conn);
    if (mysql_num_rows(table) == 0 || mysql_num_fields(table) == 0) {
      send_err(para->netfd, "user is not exist.");
      fprintf(stderr, "user: %s is not exist.\n", user_name);
      return NULL;
    }
    MYSQL_ROW row = mysql_fetch_row(table);
    strcpy(uid, row[0]);
  } else {
    sprintf(uid, "%d", u.user_id);
  }

  dirs = (DIR_S **)queryVFS(uid, &num, conn);
  if (num > 0) {
    char *buffer = (char *)malloc(4096 * sizeof(char));
    for (int i = 0; i < num; i++) {
      if (strcmp(dirs[i]->filepath, ret_path) == 0) {
        getTree(dirs[i], 0, buffer, &offset);
        break;
      } else if (strlen(ret_path) == 0 && strcmp(dirs[i]->pid,"-1") == 0) {
        getTree(dirs[i], 0, buffer, &offset);
        break;
      }
    }
    printf("Buffer: %s\n", buffer);
    freeDirs(dirs, num);
    send_tlv(para->netfd, buffer, strlen(buffer));
    free(buffer);
  } else {
    free(dirs);
  }
  return NULL;
}

int getPath_c(void *arg, MYSQL *conn) {
  Para *para = (Para *)arg;
  char *user_name = para->path[0];
  char *path = para->path[1];
  char sql[4096] = {0};
  MYSQL_RES *table = NULL;
  MYSQL_ROW row;
  int ret = -1;
  char escaped_user[256] = {0};
  char escaped_path[2048] = {0};
  mysql_real_escape_string(conn, escaped_user, user_name, strlen(user_name));
  mysql_real_escape_string(conn, escaped_path, path, strlen(path));

  snprintf(
      sql, sizeof(sql),
      "SELECT COUNT(1) FROM `user` u INNER JOIN vfs v ON u.user_id = v.user_id "
      "WHERE u.user_name = '%s' AND v.file_path = '%s'",
      escaped_user, escaped_path);

  printf("Executing SQL: %s\n", sql);

  if (mysql_query(conn, sql) != 0) {
    fprintf(stderr, "Query failed: %s\n", mysql_error(conn));
    return -1;
  }

  table = mysql_store_result(conn);
  if (!table) {
    fprintf(stderr, "Store result failed: %s\n", mysql_error(conn));
    return -1;
  }

  row = mysql_fetch_row(table);
  if (row && row[0]) {
    ret = atoi(row[0]);
  } else {
    ret = -1;
  }

  mysql_free_result(table);
  return ret; //-1  0  >0
}
